﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using HengTong.DataAccess;
using HengTong.Model.Db.Hr;
using HengTong.Model.Db.Hr.Attendance;
using HengTong.Model.Util;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Serilog;
using UUIDNext;
using WalkingTec.Mvvm.Core;

namespace HengTong.Test.HikVision
{
    /// <summary>
    /// 海康威视门禁打卡数据导入测试类
    /// </summary>
    [TestClass]
    public class HikVisionAttendanceImportTool
    {
        private ServiceProvider _serviceProvider;
        private ILogger<HikVisionAttendanceImportTool> _logger;
        private WTMContext _wtmContext;

        // 需要过滤的设备编码(正门岗)
        private static readonly HashSet<string> ExcludedDeviceIds = new HashSet<string>
        {
            "0bbe2e278a73483b9a4b27b98f2a37ec", // 正门岗出_门_1
            "5e84e2f77bc0480b91fd3757f5e6663b" // 正门岗进_门_1
        };

        [TestInitialize]
        public void TestInitialize()
        {
            // 配置文件加载
            var config = new ConfigurationBuilder()
                .AddJsonFile("appsettings.development.json", optional: true)
                .Build();

            // 配置Serilog
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Information()
                .WriteTo.Console()
                .CreateLogger();

            // 数据库上下文初始化
            var wtm = MockWtmContext.CreateWtmContext(
                new DataContext(
                    "Server=42.225.116.55,19926;Database=HengTongTest;user id=sa;password=Jia123wei!;TrustServerCertificate=True",
                    DBTypeEnum.SqlServer), "admin");
            _wtmContext = wtm;

            // 注册服务
            var services = new ServiceCollection();
            services.AddSingleton<IConfiguration>(config);
            services.AddLogging(builder => { builder.AddSerilog(dispose: true); });
            services.AddSingleton(_wtmContext);
            _serviceProvider = services.BuildServiceProvider();
            _logger = _serviceProvider.GetRequiredService<ILogger<HikVisionAttendanceImportTool>>();

            _logger.LogInformation("海康门禁数据导入测试环境初始化完成");
        }

        [TestCleanup]
        public void TestCleanup()
        {
            _wtmContext?.DC?.Dispose();
            _serviceProvider?.Dispose();
            Log.CloseAndFlush();
        }

        /// <summary>
        /// 导入昨天所有有工号的海康门禁记录
        /// </summary>
        [TestMethod]
        public async Task ImportYesterdayAttendanceRecords()
        {
            DateTime yesterday = DateTime.Now.AddDays(-1).Date;
            await ImportAttendanceRecordsForDateRange(yesterday, yesterday);
        }

        /// <summary>
        /// 导入指定日期的门禁记录
        /// </summary>
        [TestMethod]
        public async Task ImportSpecificDateAttendanceRecords()
        {
            // 示例：导入2025年10月1日的数据
            DateTime targetDate = new DateTime(2025, 10, 13);
            await ImportAttendanceRecordsForDateRange(targetDate, targetDate);
        }

        /// <summary>
        /// 导入指定日期范围的门禁记录
        /// </summary>
        [TestMethod]
        public async Task ImportDateRangeAttendanceRecords()
        {
            // 示例：导入2025年10月1日至10月10日的数据
            DateTime startDate = new DateTime(2025, 10, 12);
            DateTime endDate = new DateTime(2025, 10, 13);
            await ImportAttendanceRecordsForDateRange(startDate, endDate);
        }

        /// <summary>
        /// 导入指定日期范围的海康门禁记录
        /// </summary>
        /// <param name="startDate">开始日期</param>
        /// <param name="endDate">结束日期</param>
        private async Task ImportAttendanceRecordsForDateRange(DateTime startDate, DateTime endDate)
        {
            _logger.LogInformation(
                $"========== 开始导入从 {startDate:yyyy-MM-dd} 到 {endDate:yyyy-MM-dd} 的门禁打卡记录 ==========");
            DateTime processStart = DateTime.Now;
            int totalImported = 0;
            int totalSkipped = 0;
            int totalFailed = 0;
            int totalPersonMatched = 0;
            int totalPersonNotMatched = 0;


            try
            {
                // 获取配置
                var configuration = _serviceProvider.GetRequiredService<IConfiguration>();
                string host = configuration["AppSettings:HikVision:Host"];
                string appKey = configuration["AppSettings:HikVision:AppKey"];
                string appSecret = configuration["AppSettings:HikVision:AppSecret"];

                if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(appKey) || string.IsNullOrEmpty(appSecret))
                {
                    _logger.LogError("海康威视配置不完整，请检查appsettings.development.json配置");
                    Assert.Fail("配置缺失");
                    return;
                }

                _logger.LogInformation("海康配置信息 - Host: {Host}, AppKey: {AppKey}", host, appKey);

                var hostParts = host.Split(':');
                string ip = hostParts[0];
                int port = int.Parse(hostParts[1]);

                // 设置平台信息
                HikVisionHttpUtil.SetPlatformInfo(appKey, appSecret, ip, port, true);

                // 预加载所有员工信息到内存中，减少数据库查询
                _logger.LogInformation("预加载员工信息...");
                var allPersons = await _wtmContext.DC.Set<SysPerson>()
                    .Where(x => x.GetType() == typeof(SysPerson))
                    .Where(p => p.StaffNo != null && p.StaffNo != "")
                    .ToDictionaryAsync(p => p.StaffNo, p => p);

                _logger.LogInformation("加载了 {Count} 条员工信息", allPersons.Count);

                // 按天处理，避免一次处理大量数据
                for (DateTime currentDate = startDate; currentDate <= endDate; currentDate = currentDate.AddDays(1))
                {
                    _logger.LogInformation($"========== 处理 {currentDate:yyyy-MM-dd} 的数据 ==========");

                    // 获取当天的时间范围
                    string startTimeStr = currentDate.ToString("yyyy-MM-ddT00:00:00+08:00");
                    string endTimeStr = currentDate.AddDays(1).AddSeconds(-1).ToString("yyyy-MM-ddT23:59:59+08:00");
                    _logger.LogInformation("查询时间范围: {StartTime} 至 {EndTime}", startTimeStr, endTimeStr);

                    // 查询已导入的记录EventId
                    _logger.LogInformation("查询已导入的记录...");
                    var existingEvents = await _wtmContext.DC.Set<SysAttendanceRawRecord>()
                        .Where(r => r.PunchTime >= currentDate && r.PunchTime < currentDate.AddDays(1))
                        .Where(r => r.RawData != null && r.RawData.Contains("EventId"))
                        .Select(r => r.RawData)
                        .ToListAsync();

                    // 提取EventId
                    var existingEventIds = new HashSet<string>();
                    foreach (var rawData in existingEvents)
                    {
                        try
                        {
                            var hikEvent = JsonSerializer.Deserialize<AcsDoorEvent>(rawData);
                            if (hikEvent != null && !string.IsNullOrEmpty(hikEvent.EventId))
                            {
                                existingEventIds.Add(hikEvent.EventId);
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogWarning(ex, "解析已存在记录的EventId失败: {RawData}", rawData);
                        }
                    }

                    _logger.LogInformation("找到 {Count} 条已导入的记录", existingEventIds.Count);

                    // 分页查询参数
                    int pageNo = 1;
                    const int pageSize = 1000; // 使用最大页大小
                    bool hasMorePages = true;
                    int totalRecords = 0;
                    const int batchSize = 50; // 批量保存大小
                    int dayImported = 0, daySkipped = 0, dayFailed = 0, dayPersonMatched = 0, dayPersonNotMatched = 0;


                    // 分页查询所有门禁记录
                    while (hasMorePages)
                    {
                        // 创建请求参数
                        var requestParams = new
                        {
                            pageNo = pageNo,
                            pageSize = pageSize,
                            startTime = startTimeStr,
                            endTime = endTimeStr,
                            sort = "eventTime",
                            order = "desc"
                        };

                        string jsonBody = JsonSerializer.Serialize(requestParams);
                        _logger.LogInformation("请求参数: 页码={PageNo}, 页大小={PageSize}", pageNo, pageSize);

                        string uri = "/artemis/api/acs/v2/door/events";

                        try
                        {
                            // 调用API
                            var response =
                                await HikVisionHttpUtil.HttpPostJsonAsync<AcsDoorEventResponse>(uri, jsonBody);

                            // 检查响应
                            if (response != null && response.Code == "0" && response.Data != null)
                            {
                                totalRecords = response.Data.Total;
                                int totalPages = (totalRecords + pageSize - 1) / pageSize;

                                _logger.LogInformation("获取第 {PageNo}/{TotalPages} 页数据，总记录数: {Total}",
                                    pageNo, totalPages, totalRecords);

                                // 仅处理有工号且不是正门岗的记录，减少内存占用
                                var validEvents = response.Data.List
                                    .Where(e => !string.IsNullOrEmpty(e.jobNo) && // 过滤工号为空
                                                !ExcludedDeviceIds.Contains(e.DevIndexCode)) // 过滤正门岗设备
                                    .ToList();

                                _logger.LogInformation("本页有效记录(有工号且非正门岗): {Count}/{PageSize}",
                                    validEvents.Count, response.Data.List.Count);

                                // 批量处理记录
                                var recordBatch = new List<SysAttendanceRawRecord>(batchSize);

                                foreach (var hikEvent in validEvents)
                                {
                                    try
                                    {
                                        // 检查是否已存在
                                        if (existingEventIds.Contains(hikEvent.EventId))
                                        {
                                            daySkipped++;
                                            continue;
                                        }

                                        // 添加到已处理集合，避免重复处理
                                        existingEventIds.Add(hikEvent.EventId);

                                        // 根据工号查找对应员工
                                        allPersons.TryGetValue(hikEvent.jobNo, out var person);

                                        // 创建打卡记录
                                        var attendanceRecord = new SysAttendanceRawRecord
                                        {
                                            ID = Uuid.NewDatabaseFriendly(Database.SqlServer),
                                            PersonId = person?.ID, // 如果找到人员则关联，否则为null
                                            StaffNo = hikEvent.jobNo, // 保存原始工号，便于后续处理
                                            PunchTime = DateTime.Parse(hikEvent.EventTime),
                                            DeviceId = hikEvent.DevIndexCode,
                                            DeviceName = hikEvent.DoorName, // 使用DoorName作为设备名称
                                            Location = hikEvent.DoorName,
                                            PunchType = hikEvent.InAndOutType == 1 ? "进" :
                                                hikEvent.InAndOutType == 0 ? "出" : "未知",
                                            RecognitionType = "海康威视打卡",
                                            RawData = JsonSerializer.Serialize(hikEvent),
                                            ProcessStatus = person != null ? "已匹配人员" : "未匹配人员",
                                            ProcessTime = DateTime.Now,
                                            Remark = person != null
                                                ? $"已匹配到人员：{person.Name}"
                                                : $"未匹配到人员，原始姓名：{hikEvent.PersonName}，工号：{hikEvent.jobNo}"
                                        };

                                        recordBatch.Add(attendanceRecord);

                                        // 统计
                                        if (person != null)
                                            dayPersonMatched++;
                                        else
                                            dayPersonNotMatched++;

                                        // 批量保存
                                        if (recordBatch.Count >= batchSize)
                                        {
                                            await _wtmContext.DC.Set<SysAttendanceRawRecord>()
                                                .AddRangeAsync(recordBatch);
                                            await _wtmContext.DC.SaveChangesAsync();

                                            dayImported += recordBatch.Count;
                                            _logger.LogInformation("已导入 {Count} 条记录", dayImported);

                                            recordBatch.Clear();
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        dayFailed++;
                                        _logger.LogError(ex, "处理记录失败，EventId: {EventId}, 工号: {JobNo}",
                                            hikEvent.EventId, hikEvent.jobNo);
                                    }
                                }

                                // 保存剩余记录
                                if (recordBatch.Count > 0)
                                {
                                    await _wtmContext.DC.Set<SysAttendanceRawRecord>().AddRangeAsync(recordBatch);
                                    await _wtmContext.DC.SaveChangesAsync();

                                    dayImported += recordBatch.Count;
                                    _logger.LogInformation("已保存剩余 {Count} 条记录", recordBatch.Count);
                                    recordBatch.Clear();
                                }

                                // 判断是否还有下一页
                                if (pageNo >= totalPages || response.Data.List.Count < pageSize)
                                {
                                    hasMorePages = false;
                                }
                                else
                                {
                                    pageNo++;
                                }

                                // 清理本页数据，减少内存占用
                                response.Data.List.Clear();
                                GC.Collect();
                            }
                            else
                            {
                                _logger.LogError("API返回错误: {Code} - {Message}",
                                    response?.Code ?? "NULL", response?.Msg ?? "请求失败");
                                hasMorePages = false;
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "查询海康威视API失败，页码: {PageNo}", pageNo);
                            dayFailed++;

                            // 重试最多3次，然后继续下一页
                            if (++pageNo > 3)
                                hasMorePages = false;
                        }
                    }

                    // 输出当天统计信息
                    _logger.LogInformation("{Date} 数据导入完成! 总记录数: {Total}",
                        currentDate.ToString("yyyy-MM-dd"), totalRecords);
                    _logger.LogInformation("成功导入: {Imported}, 跳过已存在: {Skipped}, 失败: {Failed}",
                        dayImported, daySkipped, dayFailed);
                    _logger.LogInformation("人员匹配: {Matched}, 未匹配: {Unmatched}",
                        dayPersonMatched, dayPersonNotMatched);

                    // 累计总数
                    totalImported += dayImported;
                    totalSkipped += daySkipped;
                    totalFailed += dayFailed;
                    totalPersonMatched += dayPersonMatched;
                    totalPersonNotMatched += dayPersonNotMatched;
                }

                // 输出总体统计信息
                TimeSpan duration = DateTime.Now - processStart;
                _logger.LogInformation("========== 所有日期数据导入完成! ==========");
                _logger.LogInformation("总耗时: {Duration:hh\\:mm\\:ss}", duration);
                _logger.LogInformation("总导入: {Imported}, 总跳过: {Skipped}, 总失败: {Failed}",
                    totalImported, totalSkipped, totalFailed);
                _logger.LogInformation("总人员匹配: {Matched}, 总未匹配: {Unmatched}",
                    totalPersonMatched, totalPersonNotMatched);

                Assert.IsTrue(totalImported > 0 || totalSkipped > 0, "未找到任何需要导入的门禁记录");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "导入门禁记录过程中发生异常");
                Assert.Fail($"导入失败: {ex.Message}");
            }
        }
    }
}